package com.shuyu.web.controller.platform;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.shuyu.common.core.controller.BaseController;
import com.shuyu.common.core.domain.AjaxResult;
import com.shuyu.common.core.page.TableDataInfo;
import com.shuyu.common.enums.OperationType;
import com.shuyu.common.exception.ServiceException;
import com.shuyu.common.utils.StringUtils;
import com.shuyu.common.utils.poi.ExcelUtil;
import com.shuyu.domain.NFT;
import com.shuyu.domain.Product;
import com.shuyu.domain.ProductTmp;
import com.shuyu.service.*;
import com.shuyu.vo.CardVo;
import com.shuyu.vo.NFTImportVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 授权登录相关
 * 
 * @author
 */
@RestController
@RequestMapping("/platform/product")
@Api(tags = "产品管理")
public class PProductController extends BaseController
{
    @Resource
    private ProductService productService;
    @Resource
    private ApprovalProcessDetailService approvalProcessDetailService;
    @Resource
    private NFTService nftService;
    @Resource
    private ProductTmpService productTmpService;
    @Resource
    private ProductCardCodeService productCardCodeService;



    @PreAuthorize("@ss.hasPermi('system:product:list')")
    @GetMapping("/list")
    @ApiOperation("查询产品列表")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name", value = "名称", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "auditStatus", value = "审核状态0待审核 1审核完成 2 审核驳回", dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "type", value = "产品类型1:NFT;2:卡牌;3:MV;4:内部权益;5:外部权益", dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "priceOrder", value = "产品价值筛选 desc：价格降序 asc：价格升序 ", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "stockOrder", value = "库存筛选 desc：库存降序 asc：库存升序 ", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "album", value = "所属专辑", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "issuingCompany", value = "发行公司", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "productionCompany", value = "制作公司", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "source", value = "权益来源:1:大有;2:中葡;3:敦煌文化;", dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "cardType", value = "卡牌类型", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "startTime", value = "到期日开始时间", dataType = "Date", dataTypeClass = Date.class),
            @ApiImplicitParam(name = "endTime", value = "到期日结束时间", dataType = "Date", dataTypeClass = Date.class),
            @ApiImplicitParam(name = "nftName", value = "对应NFT", dataType = "String", dataTypeClass = String.class),

    })
    public TableDataInfo list(Integer type,String priceOrder,String name,Integer auditStatus,String stockOrder,String album
            ,String issuingCompany, String productionCompany,Integer source, String cardType,String startTime, String endTime
            ,String nftName)
    {
        startPage();
        LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<Product>()
                .eq(Product::getDelFlag,0).eq(Product::getType,type)
                .like(StringUtils.isNotEmpty(name),Product::getName,name)
                .eq(ObjectUtil.isNotNull(auditStatus),Product::getAuditStatus,auditStatus)
                .eq(StringUtils.isNotEmpty(album),Product::getAlbum,album)
                .like(StringUtils.isNotEmpty(issuingCompany),Product::getIssuingCompany,issuingCompany)
                .like(StringUtils.isNotEmpty(productionCompany),Product::getProductionCompany,productionCompany)
                .eq(ObjectUtil.isNotNull(source),Product::getSource,source)
                .eq(StringUtils.isNotEmpty(cardType),Product::getCardType,cardType)
                .le(StringUtils.isNotEmpty(endTime),Product::getEquityEndTime, endTime)
                .ge(StringUtils.isNotEmpty(startTime),Product::getEquityEndTime, startTime);
        if(type == 2 && StringUtils.isNotEmpty(nftName)){
            List<Product> productList = productService.list(new LambdaQueryWrapper<Product>().like(Product::getName, nftName));
            if(CollectionUtil.isNotEmpty(productList)){
                List<Integer> integerList = productList.stream().map(Product::getId).collect(Collectors.toList());
                wrapper.in(Product::getProductId,integerList);
            }else {
                wrapper.eq(Product::getProductId,-999);
            }
        }
        if(StringUtils.isNotEmpty(priceOrder)){
            if(priceOrder.equalsIgnoreCase("asc")){
                wrapper.orderByAsc(Product::getPrice);
            }else {
                wrapper.orderByDesc(Product::getPrice);
            }
        }
        if(StringUtils.isNotEmpty(stockOrder)){
            if(stockOrder.equalsIgnoreCase("asc")){
                wrapper.orderByAsc(Product::getStock);
            }else {
                wrapper.orderByDesc(Product::getStock);
            }
        }
        wrapper.orderByDesc(Product::getCreateTime);
        List<Product> list = productService.list(wrapper);
        for (Product product : list) {
            setNftList(product);
        }
        return getDataTable(list);
    }

    public static void main(String[] args) {
        String a = null;
        System.out.println(StringUtils.isNotEmpty(a));
    }
    @GetMapping("/getAll")
    @ApiOperation("查询获取所有产品列表")
    public AjaxResult getAll()
    {
        List<Product> list = productService.list(new LambdaQueryWrapper<Product>().eq(Product::getDelFlag,0).eq(Product::getStatus,0)
                .orderByDesc(Product::getCreateTime));
        Map<String, List<Product>> collect = list.stream().collect(Collectors.groupingBy(Product::getTypeName));
        List<Map<String,Object>> result = new ArrayList<>();
        collect.forEach((key,value)->{
            Map<String,Object> map = new HashMap<>();
            map.put("name",key);
            map.put("children",value);
            result.add(map);
        });
        return AjaxResult.success(result);
    }
    @GetMapping("/getAllCard")
    @ApiOperation("查询获取所有卡牌产品列表")
    public AjaxResult getAllCard()
    {
        return AjaxResult.success(getProductList(2));
    }
    @GetMapping("/getAllNft")
    @ApiOperation("查询获取所有NFT产品列表")
    public AjaxResult getAllNft()
    {
        return AjaxResult.success(getProductList(1));
    }
    private List<Product> getProductList(int type){
        return productService.list(new LambdaQueryWrapper<Product>().eq(Product::getDelFlag,0).eq(Product::getStatus,0).eq(Product::getType,type)
                .orderByDesc(Product::getCreateTime));
    }

    @PreAuthorize("@ss.hasPermi('system:product:add')")
    @PostMapping
    @ApiOperation("添加产品")
    public AjaxResult add(@RequestBody Product product){
        product.setCreateTime(new Date());
        product.setAuditStatus(0);
        product.setStatus(1);
        product.setOperationType(OperationType.上架.type);
        boolean save = productService.save(product);
        approvalProcessDetailService.createApprovalProcess(1, OperationType.上架.type, product.getId());
        return toAjax(save);
    }
    @PreAuthorize("@ss.hasPermi('system:product:update')")
    @PutMapping
    @ApiOperation("修改产品")
    public AjaxResult update(@RequestBody ProductTmp product){
        int productId= product.getId();
        checkAuditStatus(productId);
        Product byIdProduct = productService.getById(productId);
        if(byIdProduct.getType()==1&&byIdProduct.getNftCreateTaskStatus()==1){
            throw new ServiceException("NFT已生成，不允许修改NFT");
        }
        productTmpService.remove(new LambdaQueryWrapper<ProductTmp>().eq(ProductTmp::getPId,productId));
        product.setPId(productId);
        product.setId(null);
        product.setCreateTime(new Date());
        boolean save = productTmpService.save(product);
        approvalProcessDetailService.createApprovalProcess(1, OperationType.修改.type,productId);
        Product pt = new Product();
        pt.setAuditStatus(0);
        pt.setId(productId);
        pt.setOperationType(OperationType.修改.type);
        productService.updateById(pt);
//        if(product.getProductId()!=null&&product.getProductId()==-1){
//            productService.update(new LambdaUpdateWrapper<Product>().set(Product::getProductId,null).eq(Product::getId, product.getId()));
//        }
        return toAjax(save);
    }
    private void checkAuditStatus(int productId){
        int count = productService.count(new LambdaQueryWrapper<Product>().eq(Product::getAuditStatus, 0).eq(Product::getId, productId));
        if(count>0){
            throw new ServiceException("审核未完成，不允许再去发起审核");
        }
    }

    @PreAuthorize("@ss.hasPermi('system:product:del')")
    @DeleteMapping("/{id}")
    @ApiOperation("删除产品")
    public AjaxResult del(@PathVariable int id){
        checkAuditStatus(id);
        Product product = new Product();
        product.setId(id);
        product.setAuditStatus(0);
        product.setOperationType(OperationType.删除.type);
        product.setModifyTime(new Date());
        boolean b = productService.updateById(product);
        approvalProcessDetailService.createApprovalProcess(1, OperationType.删除.type,product.getId());
        return toAjax(b);
    }
    @GetMapping("/{id}")
    @ApiOperation("获取产品详情")
    public AjaxResult detail(@PathVariable int id){
        Product product = productService.getById(id);
        setNftList(product);
        AjaxResult ajax = AjaxResult.success(product);
        if(product.getAuditStatus()==0&&product.getOperationType()==OperationType.修改.type){
            ProductTmp productTmp = productTmpService.getOne(new LambdaQueryWrapper<ProductTmp>().eq(ProductTmp::getPId,id).last("limit 1"));
            ajax.put("dataEx", productTmp);
        }
        return ajax;
    }
    @PutMapping("/updateStock")
    @ApiOperation("修改产品库存")
    public AjaxResult updateStock(@RequestBody Product product){
        return AjaxResult.success(productService.updateById(product));
    }

    @PutMapping("/updateStatus")
    @ApiOperation("修改上下架状态")
    public AjaxResult updateStatus(@RequestBody Product product){
        checkAuditStatus(product.getId());
        Product pt = new Product();
        if(product.getStatus()==0){
            pt.setOperationType(OperationType.上架.type);
            approvalProcessDetailService.createApprovalProcess(1, OperationType.上架.type,product.getId());
        }else if(product.getStatus()==1) {
            pt.setOperationType(OperationType.下架.type);
            approvalProcessDetailService.createApprovalProcess(1, OperationType.下架.type,product.getId());
        }

        pt.setAuditStatus(0);
        pt.setId(product.getId());
        productService.updateById(pt);
        return AjaxResult.success();
    }

    private void  setNftList(Product product){
        Integer type = product.getType();
        if(type ==1){
            List<NFT> nftList = nftService.list(new LambdaUpdateWrapper<NFT>().eq(NFT::getProductId, product.getId()));
            product.setNftList(nftList);
        }else if(type ==  2){
            if(product.getNftStatus() == 1) {
                Product pd = productService.getById(product.getProductId());
                if (ObjectUtil.isNotNull(pd)) {
                    product.setNftName(pd.getName());
//                    List<NFT> nftList = nftService.list(new LambdaUpdateWrapper<NFT>().eq(NFT::getProductId, pd.getId()));
                    List<NFT> nftList = nftService.getNFTList(pd.getId());
                    product.setNftList(nftList);
                }
            }else {
                if(product.getPoint()>0){
                    List<NFT> nftList = productCardCodeService.getNFTList(product.getId());
                    product.setNftList(nftList);
                }
            }
        }
    }

    @PostMapping("/export/{id}")
    @ApiOperation("导出卡牌数据")
    public void export(HttpServletResponse response,@PathVariable int id)
    {
        Product product = productService.getById(id);
        List<NFT> nftList = new ArrayList<>();
        if(product.getNftStatus()==1){
            nftList = nftService.list(new LambdaUpdateWrapper<NFT>().eq(NFT::getProductId, product.getProductId()));
            product.setQuantity(nftList.size());
        }else {
            if(product.getQuantity()==null){
                product.setQuantity(product.getStock());
            }
        }
        List<CardVo> list = new ArrayList<>();
        for (Integer i = 0; i < product.getQuantity(); i++) {
            String transactionHash = null;
            if(product.getNftStatus()==1){
                transactionHash = nftList.get(i).getTransactionHash();
            }
            CardVo cardVo = new CardVo(i+1, product.getName(), product.getCardSerial(), null, transactionHash);
            list.add(cardVo);
        }
        ExcelUtil<CardVo> util = new ExcelUtil<>(CardVo.class);
        util.exportExcel(response, list, "卡牌数据");
    }
    @PostMapping("/importData/{id}")
    @ApiOperation("导入卡牌数据")
    public AjaxResult importData(MultipartFile file,@PathVariable int id) throws Exception
    {
        ExcelUtil<CardVo> util = new ExcelUtil<>(CardVo.class);
        List<CardVo> cardList = util.importExcel(file.getInputStream());
        String operName = getUsername();
        String message = nftService.importCard(cardList, id, operName);
        return success(message);
    }

    @PostMapping("/importDataNFt")
    @ApiOperation("导入NFT数据")
    public AjaxResult importDataNFt(MultipartFile file) throws Exception
    {
        ExcelUtil<NFTImportVo> util = new ExcelUtil<>(NFTImportVo.class);
        List<NFTImportVo> nftImportVos = util.importExcel(file.getInputStream());
        for (NFTImportVo nftImportVo : nftImportVos) {
            Product product = new Product();
            product.setName(nftImportVo.getName());
            product.setIntroduction(nftImportVo.getIntroduction());
            product.setImg(nftImportVo.getImg());
            product.setIssuingCompany(nftImportVo.getIssuingCompany());
            product.setProductionCompany(nftImportVo.getProductionCompany());
            product.setQuantity(nftImportVo.getQuantity());
            product.setContractAddress(nftImportVo.getContractAddress());
            product.setProductId(-1);
            product.setType(1);
            add(product);
        }
        return success();
    }

}
